/**
 * 
 */
package patternRecognition.COMP6731.Assignment2;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

/**
 * @author p_sokke
 *
 */

public class ReadBinaryImage {

	static int row;
	static int column;

	
	public static void main(String[] args) {
		// Read the Binary Image file from resource folder
		int inputMatrix[][] = ReadBinaryImage.loadBinaryImage();

		System.out.println("Row Count:\t" + row);
		System.out.println("Column Count:\t" + column);
		System.out.println("Input Binary Image:\n");
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < column; j++) {
				// System.out.print(a2Array[i][j]);
				if (inputMatrix[i][j] == 1)
					System.out.print(inputMatrix[i][j]);
				else
					System.out.print(" ");
			}
			System.out.println();
		}
		
		System.out.println("\t Matrix row size: \t" + inputMatrix.length);
		System.out.println("\t Matrix col size: \t" + inputMatrix[0].length);

		// Smoothing with filtering
		// http://nayefreza.wordpress.com/2013/05/12/smoothing-binary-image-using-3x3-filter-mask-java-implementation/
		BinaryImagePreProcessing binaryImagePreProcessing = new BinaryImagePreProcessing();
		int resultMatrix[][] = binaryImagePreProcessing.binaryImageSmoothing(inputMatrix, row, column);

		System.out.println("\nSmoothened Binary Image:\n");
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < column; j++) {
				// System.out.print(a2Array[i][j]);
				if (resultMatrix[i][j] == 1)
					System.out.print(resultMatrix[i][j]);
				else
					System.out.print(" ");
			}
			System.out.println();
		}
		
		
				
//		4 neighbour filling 
		for (int k = 1; k <= 0; k++) {
			resultMatrix = fill4NeighbourBinaryImage(resultMatrix);

			System.out.println("\nfill4NeighbourBinaryImage\nFilled Binary Image \t" + k + "th time:\n");
			for (int i = 0; i < row; i++) {
				for (int j = 0; j < column; j++) {
					// System.out.print(a2Array[i][j]);
					if (resultMatrix[i][j] == 1)
						System.out.print(resultMatrix[i][j]);
					else
						System.out.print(" ");
				}
				System.out.println();
			}
		}
		
//		8 neighbour filling1
		for (int k = 1; k <= 5; k++) {
			resultMatrix = fill8NeighbourBinaryImage(resultMatrix);
			System.out.println("\nfill8NeighbourBinaryImage\nFilled Binary Image \t" + k + "th time:\n");
		
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < column; j++) {
				// System.out.print(a2Array[i][j]);
				if (resultMatrix[i][j] == 1)
					System.out.print(resultMatrix[i][j]);
				else
					System.out.print(" ");
			}
			System.out.println();
		}
		}
		
		
//		Size normalization
		resultMatrix = sizeNormalization(resultMatrix, row, column);
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < column; j++) {
				// System.out.print(a2Array[i][j]);
				if (resultMatrix[i][j] == 1)
					System.out.print(resultMatrix[i][j]);
				else
					System.out.print(" ");
			}
			System.out.println();
		}
		
		int[][] resultMatrix2 = resultMatrix;
		
//		ZhangSuenThinning
		ZhangSuenThinning zhangSuenThinning = new ZhangSuenThinning();
		resultMatrix = zhangSuenThinning.applyZhangSuenThinning(resultMatrix, row, column);
		System.out.println("\napplyZhangSuenThinning\nFilled Binary Image \t" + 1 + "th time:\n");
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < column; j++) {
				// System.out.print(a2Array[i][j]);
				if (resultMatrix[i][j] == 1)
					System.out.print(resultMatrix[i][j]);
				else
					System.out.print(" ");
			}
			System.out.println();
		}
		
		System.out.println("\t resultMatrix row size: \t" + resultMatrix.length);
		System.out.println("\t resultMatrix col size: \t" + resultMatrix[0].length);
		
//		Thinning Binary Image
		resultMatrix2 = thinningBinaryImage(resultMatrix2);
		System.out.println("\nThinningBinaryImage\nAfter Thinning Binary Image \t" + 1 + "th time:\n");
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < column; j++) {
				// System.out.print(a2Array[i][j]);
				if (resultMatrix2[i][j] == 1)
					System.out.print(resultMatrix2[i][j]);
				else
					System.out.print(" ");
			}
			System.out.println();
		}
		
		
		
		/*
		 * int filledMatrix[][] = fillBinaryImage(smoothMatrix);
		 * 
		 * System.out.println("\nFilled Binary Image:\n"); for (int i = 0; i <
		 * row; i++) { for (int j = 0; j < col; j++){ //
		 * System.out.print(a2Array[i][j]); if(filledMatrix[i][j] == 1)
		 * System.out.print(filledMatrix[i][j]); else System.out.print(" "); }
		 * System.out.println(); }
		 */

//		int filledMatrix[][] = new int[10000][10000];

		

		/*
		 * 
		 * // Enhancement using filling // if abcdefgh = 1, x = 1, // else if
		 * a+b+c+d+f+g+h = 0, x=0 int e2Array[][] = enhanceBinaryImage(s2Array);
		 * System.out.println("\nEnhanced Binary Image:\n"); for (int i = 0; i <
		 * row; i++) { for (int j = 0; j < col; j++){ //
		 * System.out.print(a2Array[i][j]); if(s2Array[i][j] == 1)
		 * System.out.print(e2Array[i][j]); else System.out.print(" "); }
		 * System.out.println(); }
		 * 
		 * // Filliing 4 direct neighbours // if any 3 direct neighbours are 1
		 * fill int d2Array[][] = neighbourBinaryImage(e2Array);
		 * System.out.println("\n4 direct neighbour Binary Image:\n"); for (int
		 * i = 0; i < row; i++) { for (int j = 0; j < col; j++){ //
		 * System.out.print(a2Array[i][j]); if(s2Array[i][j] == 1)
		 * System.out.print(e2Array[i][j]); else System.out.print(" "); }
		 * System.out.println(); } System.out.println("\n\n\nasdf\n\n\n"); for
		 * (int i = 0; i < 50; i++) { d2Array = neighbourBinaryImage(d2Array); }
		 * 
		 * System.out.println("\n4 direct neighbour Binary Image:\n"); for (int
		 * i = 0; i < row; i++) { for (int j = 0; j < col; j++){ //
		 * System.out.print(a2Array[i][j]); if(s2Array[i][j] == 1)
		 * System.out.print(e2Array[i][j]); else System.out.print(" "); }
		 * System.out.println(); }
		 * 
		 * int fs2Array[][] = fillingBySmoothingBinaryImage(d2Array);
		 */

	}
	
	

	private static int[][] sizeNormalization(int[][] binaryMatrix, int row, int column) {
		int[][] resultMatrix = new int[1000][1000];
		int iRow = 0;
		int iColumn = 0;
		for(int x = 1; x < row; x++){
			for(int y = 1; y < column; y++){
				int i = x / 2 ;
				int j = y / 2;
				resultMatrix[i][j] = binaryMatrix[x][y];
				iRow = i;
				iColumn = j;
			}
		}
		System.out.println(iRow);
		System.out.println(iColumn);
		return resultMatrix;
	}



	private static int[][] thinningBinaryImage(int[][] binaryMatrix) {
		for (int i = 1; i < row - 1; i++) {
			for (int j = 1; j < column - 1; j++) {
				boolean targetBit = (binaryMatrix[i][j] == 1) ? true : false;
				
				boolean leftBit  = (binaryMatrix[i][j - 1] == 1) ? true : false;
				boolean rightBit = (binaryMatrix[i][j + 1] == 1) ? true : false;
				boolean upperBit = (binaryMatrix[i - 1][j] == 1) ? true : false;
				boolean lowerBit = (binaryMatrix[i + 1][j] == 1) ? true : false;
				
				boolean leftUpperBit = (binaryMatrix[i - 1][j - 1] == 1) ? true : false;
				boolean leftLowerBit = (binaryMatrix[i + 1][j - 1] == 1) ? true : false;
				boolean rightUpperBit = (binaryMatrix[i - 1][j + 1] == 1) ? true : false;
				boolean rightLowerBit = (binaryMatrix[i + 1][j + 1] == 1) ? true : false;

				boolean resultBit = targetBit | ( ( leftUpperBit  & leftBit  & upperBit ) 
												& ( rightUpperBit & rightBit & upperBit ) 
												& ( leftLowerBit  & leftBit  & lowerBit ) 
												& ( rightLowerBit & rightBit & lowerBit ) );
				binaryMatrix[i][j] = (resultBit) ? 1 : 0;
//				if (resultBit)
//					System.out.println("row:\t" + i + "col:\t" + j);
			}
		}
		return binaryMatrix;
	}

	

	private static int[][] fillingBySmoothingBinaryImage(int[][] fs2Array) {
		for (int i = 1; i < row - 1; i++) {
			for (int j = 1; j < column - 1; j++) {
				int indexValue = fs2Array[i][j];
				if (indexValue == 1) {
					if (fs2Array[i - 1][j - 1] == 1 || fs2Array[i][j - 1] == 1
							|| fs2Array[i + 1][j - 1] == 1
							|| fs2Array[i - 1][j] == 1
							|| fs2Array[i + 1][j] == 1
							|| fs2Array[i - 1][j + 1] == 1
							|| fs2Array[i][j + 1] == 1
							|| fs2Array[i + 1][j + 1] == 1) {
						fs2Array[i][j] = 1;
					}
				}
			}
		}
		return fs2Array;
	}

	private static int[][] neighbourBinaryImage(int[][] d2Array) {
		for (int i = 1; i < row - 1; i++) {
			for (int j = 1; j < column - 1; j++) {
				int count = 0;
				if (d2Array[i - 1][j] == 1)
					++count;
				if (d2Array[i + 1][j] == 1)
					++count;
				if (d2Array[i][j - 1] == 1)
					++count;
				if (d2Array[i][j + 1] == 1)
					++count;
				if (count > 2) {
					// System.out.println("Changed:\trow\t" + i + "col:\t" + j);
					d2Array[i][j] = 1;
				}
				count = 0;
			}
		}

		return d2Array;
	}

	private static int[][] enhanceBinaryImage(int[][] s2Array) {

		for (int i = row - 2; i > 0; i--) {
			for (int j = column - 2; j > 0; j--) {
				// if(){
				//
				if (s2Array[i - 1][j - 1] == 1 && s2Array[i][j - 1] == 1
						&& s2Array[i + 1][j - 1] == 1 && s2Array[i - 1][j] == 1
						&& s2Array[i + 1][j] == 1 && s2Array[i - 1][j + 1] == 1
						&& s2Array[i][j + 1] == 1 && s2Array[i + 1][j + 1] == 1) {
					System.out.println("Changed:\trow\t" + i + "col:\t" + j);
					s2Array[i][j] = 1;
				}

				// }
			}
		}

		return s2Array;
	}

	public static int[][] loadBinaryImage() {
		String a2Image = "resource/Assignment2Binary.txt";
		int tempRow = 0;
		int tempCol = 0;
		int a2Array[][] = new int[1000][1000];
		try {
			Scanner input = new Scanner(new File(a2Image));
			while (input.hasNextLine()) {
				String line = input.nextLine();
				tempCol = line.length();
				for (int i = 0; i < tempCol; i++) {
					a2Array[tempRow][i] = Integer.parseInt(String.valueOf(line
							.charAt(i)));
				}
				++tempRow;
			}
			input.close();
			row = tempRow;
			column = tempCol;
		} catch (FileNotFoundException fnf) {
			fnf.printStackTrace();
		}
		return a2Array;
	}

//	
//	private static int[][] smoothBinaryImage(int[][] binaryImage) {
//
//		boolean hasChange;
//		int filterVal = 3;
//		do {
//			hasChange = false;
//			for (int y = binaryImage.length - 2; y > 0; y--) {
//				for (int x = binaryImage[y].length - 2; x > 0; x--) {
//					hasChange = hasChange
//							|| smoothPoint(binaryImage, y, x, filterVal);
//				}
//			}
//
//			filterVal++;
//			filterVal = filterVal % 4;
//
//		} while (hasChange);
//
//		return binaryImage;
//	}
//
//	private static boolean smoothPoint(int[][] binaryImage, int y, int x,
//			int filterVal) {
//
//		if (filterVal == 0
//				&& binaryImage[y][x - 1] == binaryImage[y - 1][x - 1]
//				&& binaryImage[y - 1][x - 1] == binaryImage[y - 1][x]
//				&& binaryImage[y - 1][x] == binaryImage[y - 1][x + 1]
//				&& binaryImage[y - 1][x + 1] == binaryImage[y][x + 1]
//				&& binaryImage[y][x] != binaryImage[y][x - 1]) {
//
//			binaryImage[y][x] = binaryImage[y][x - 1];
//			return true;
//		}
//
//		if (filterVal == 1
//				&& binaryImage[y - 1][x] == binaryImage[y - 1][x + 1]
//				&& binaryImage[y - 1][x + 1] == binaryImage[y][x + 1]
//				&& binaryImage[y][x + 1] == binaryImage[y + 1][x + 1]
//				&& binaryImage[y + 1][x + 1] == binaryImage[y + 1][x]
//				&& binaryImage[y][x] != binaryImage[y - 1][x]) {
//
//			binaryImage[y][x] = binaryImage[y - 1][x];
//			return true;
//		}
//
//		if (filterVal == 2
//				&& binaryImage[y][x + 1] == binaryImage[y + 1][x + 1]
//				&& binaryImage[y + 1][x + 1] == binaryImage[y + 1][x]
//				&& binaryImage[y + 1][x] == binaryImage[y + 1][x - 1]
//				&& binaryImage[y + 1][x - 1] == binaryImage[y][x - 1]
//				&& binaryImage[y][x] != binaryImage[y][x + 1]) {
//
//			binaryImage[y][x] = binaryImage[y][x + 1];
//			return true;
//		}
//
//		if (filterVal == 3
//				&& binaryImage[y + 1][x] == binaryImage[y + 1][x - 1]
//				&& binaryImage[y + 1][x - 1] == binaryImage[y][x - 1]
//				&& binaryImage[y][x - 1] == binaryImage[y - 1][x - 1]
//				&& binaryImage[y - 1][x - 1] == binaryImage[y - 1][x]
//				&& binaryImage[y][x] != binaryImage[y + 1][x]) {
//
//			binaryImage[y][x] = binaryImage[y + 1][x];
//			return true;
//		}
//
//		return false;
//
//	}
//	
//	
	
	private static int[][] fill4NeighbourBinaryImage(int[][] binaryMatrix) {
		for (int i = 1; i < row - 1; i++) {
			for (int j = 1; j < column - 1; j++) {
				int target = binaryMatrix[i][j];
				boolean targetBit = (binaryMatrix[i][j] == 1) ? true : false;
				if (!targetBit) {
					boolean leftBit  = (binaryMatrix[i][j - 1] == 1) ? true : false;
					boolean rightBit = (binaryMatrix[i][j + 1] == 1) ? true : false;
					boolean upperBit = (binaryMatrix[i - 1][j] == 1) ? true : false;
					boolean lowerBit = (binaryMatrix[i + 1][j] == 1) ? true : false;

					boolean resultBit = ((targetBit)
							| ((upperBit & lowerBit) & (leftBit | rightBit)) 
							| ((leftBit & rightBit) & (upperBit | lowerBit)));
					binaryMatrix[i][j] = (resultBit) ? 1 : 0;
					if (resultBit)
						System.out.println("row:\t" + i + "col:\t" + j);
				}
			}
		}
		return binaryMatrix;
	}
	
	private static int[][] fill8NeighbourBinaryImage(int[][] binaryMatrix) {
		for (int i = 1; i < row - 1; i++) {
			for (int j = 1; j < column - 1; j++) {
				int target = binaryMatrix[i][j];
				boolean targetBit = (binaryMatrix[i][j] == 1) ? true : false;
					
				boolean leftBit  = (binaryMatrix[i][j - 1] == 1) ? true : false;
				boolean rightBit = (binaryMatrix[i][j + 1] == 1) ? true : false;
				boolean upperBit = (binaryMatrix[i - 1][j] == 1) ? true : false;
				boolean lowerBit = (binaryMatrix[i + 1][j] == 1) ? true : false;
				
				boolean leftUpperBit = (binaryMatrix[i - 1][j - 1] == 1) ? true : false;
				boolean leftLowerBit = (binaryMatrix[i + 1][j - 1] == 1) ? true : false;
				boolean rightUpperBit = (binaryMatrix[i - 1][j + 1] == 1) ? true : false;
				boolean rightLowerBit = (binaryMatrix[i + 1][j + 1] == 1) ? true : false;

//					boolean resultBit = upperBit & lowerBit & leftBit & rightBit & 
//										leftUpperBit & leftLowerBit & rightUpperBit & rightLowerBit ;
				
				boolean resultBit = ( ( targetBit ) | ( leftUpperBit & rightLowerBit ) | ( upperBit & lowerBit ) | ( rightUpperBit & leftLowerBit ) | ( leftBit & rightBit ) );
				
					binaryMatrix[i][j] = (resultBit) ? 1 : 0;
					if (resultBit){
					System.out.println("row:\t" + i + "col:\t" + j);
				}
			}
		}
		return binaryMatrix;
	}

}
